Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store both the rounded and unrounded node size in Node #9923

Merged
merged 8 commits into from
Sep 28, 2023

Conversation

ickshonpe
Copy link
Contributor

@ickshonpe ickshonpe commented Sep 25, 2023

Objective

Text bounds are computed by the layout algorithm using the text's measurefunc so that text will only wrap after it's used the maximum amount of available horizontal space.

When the layout size is returned the layout coordinates are rounded and this sometimes results in the final size of the Node not matching the size computed with the measurefunc. This means that the text may no longer fit the horizontal available space and instead wrap onto a new line. However, no glyphs will be generated for this new line because no vertical space for the extra line was allocated.

fixes #9874

Solution

Store both the rounded and unrounded node sizes in Node.

Rounding is used to eliminate pixel-wide gaps between nodes that should be touching edge to edge, but this isn't necessary for text nodes as they don't have solid edges.

Changelog

  • Added the rounded_size: Vec2 field to Node.
  • text_system uses the unrounded node size when computing a text layout.

…that given whatever the constraints are text will only wrap after it's used the maximum amount of available horizontal space.

However then when the layout size is returned, before the Node size is set the layout coordinates are rounded, sometimes changing the size of the Node. This means that the text may no longer fit the horizontal available space and wrap onto a new line. But since the layout algorithm hasn't alloted any vertical space for this new line, the text on this new line dissappears.

The commit adds a flag `no_rounding` to `ContentSize` that tells the layout algorithm not to round the size of the node, avoiding this problem.

Rounding is used eliminate pixel wide gaps between nodes that should be touching edge to edge, but this isn't necessary for text nodes as they don't have solid edges.
@ickshonpe ickshonpe changed the title Make rounding optional for nodes with a ContentSize. Make rounding optional for nodes with a ContentSize Sep 25, 2023
@ickshonpe ickshonpe changed the title Make rounding optional for nodes with a ContentSize Optional rounding for nodes with a ContentSize Sep 25, 2023
Copy link
Contributor

@nicoburns nicoburns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to me. I think the general principle is:

Rounding (pixel-grid alignment) should never affect layout, and should be for rendering only.

For text, I suspect that might mean passing the unrounded value into text layout, and then clipping to the rounded value when rendering.

@nicoburns nicoburns added C-Bug An unexpected or incorrect behavior A-UI Graphical user interfaces, styles, layouts, and widgets labels Sep 26, 2023
@ickshonpe
Copy link
Contributor Author

ickshonpe commented Sep 26, 2023

This makes sense to me. I think the general principle is:

Rounding (pixel-grid alignment) should never affect layout, and should be for rendering only.

For text, I suspect that might mean passing the unrounded value into text layout, and then clipping to the rounded value when rendering.

Yeah it needs a lot of thinking about. I also considered just adding both the rounded and unrounded sizes to Node. I was feeling before that it would be a bit redundant and a waste of memory, but maybe it's the better solution.

@nicoburns
Copy link
Contributor

In theory, you shouldn't need to perform text layout again once Taffy's layout has completed. But I'm guessing our current text infrastructure doesn't allow us to reuse the result? We ended up having to store both in Taffy, because otherwise we can't cache results from previous layout runs (as they might round differently if their parents lay out differently and they end up in a different absolute position within the viewport).

@rparrett
Copy link
Contributor

rparrett commented Sep 27, 2023

I tested every example at scale factor 2., and this seems to fix text layout problems with quite a few of them and doesn't seem to introduce any new problems.

The ones that had differences were

display_and_visibility
overflow
text_wrap_debug
overflow_debug
ui
text_debug

For other scale factors, I only tested the examples listed above.

At scale factor 4./3., this seems to fix some text wrapping issues, but also introduces a 1px gap in text_wrap_debug.

Seemingly the same story at 1.0 -- text layout is better, but 1px gap in text_wrap_debug.

Instead, store the both the unrounded and rounded sizes in `Node`.
@ickshonpe ickshonpe changed the title Optional rounding for nodes with a ContentSize Store both the rounded and unrounded node size in Node Sep 27, 2023
@ickshonpe
Copy link
Contributor Author

Switched approach to storing both the rounded and unrounded node sizes in Node.

@ickshonpe
Copy link
Contributor Author

ickshonpe commented Sep 27, 2023

I tested every example at scale factor 2., and this seems to fix text layout problems with quite a few of them and doesn't seem to introduce any new problems.

The ones that had differences were

display_and_visibility
overflow
text_wrap_debug
overflow_debug
ui
text_debug

For other scale factors, I only tested the examples listed above.

At scale factor 4./3., this seems to fix some text wrapping issues, but also introduces a 1px gap in text_wrap_debug.

Seemingly the same story at 1.0 -- text layout is better, but 1px gap in text_wrap_debug.

I think the gaps should be gone now with the new approach. Text can use the unrounded bounds for layout calculations but the size of any node containing text will remain rounded, so there shouldn't be any gaps in the layout. How does it look for you now?

Co-authored-by: Rob Parrett <robparrett@gmail.com>
Copy link
Contributor

@rparrett rparrett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love how simple this version is.

Did some more testing using my collection of screenshot diffing scripts vs the base commit

  • All examples at SF 2
  • UI examples at SF 1, 4/3, 5/3

Looks good to me. Minor changes in text wrapping behavior that seem more correct, and seemingly no unintended consequences.

@nicoburns nicoburns added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Sep 28, 2023
@mockersf mockersf added this pull request to the merge queue Sep 28, 2023
Merged via the queue into bevyengine:main with commit edba496 Sep 28, 2023
22 checks passed
@cart cart mentioned this pull request Oct 13, 2023
43 tasks
rdrpenguin04 pushed a commit to rdrpenguin04/bevy that referenced this pull request Jan 9, 2024
# Objective

Text bounds are computed by the layout algorithm using the text's
measurefunc so that text will only wrap after it's used the maximum
amount of available horizontal space.

When the layout size is returned the layout coordinates are rounded and
this sometimes results in the final size of the Node not matching the
size computed with the measurefunc. This means that the text may no
longer fit the horizontal available space and instead wrap onto a new
line. However, no glyphs will be generated for this new line because no
vertical space for the extra line was allocated.

fixes bevyengine#9874

## Solution

Store both the rounded and unrounded node sizes in `Node`.

Rounding is used to eliminate pixel-wide gaps between nodes that should
be touching edge to edge, but this isn't necessary for text nodes as
they don't have solid edges.

## Changelog

* Added the `rounded_size: Vec2` field to `Node`.
* `text_system` uses the unrounded node size when computing a text
layout.

---------

Co-authored-by: Rob Parrett <robparrett@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-UI Graphical user interfaces, styles, layouts, and widgets C-Bug An unexpected or incorrect behavior S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Text wraps incorrectly for a frame after a change to its font size
4 participants